package com.beidouapp.common.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.sf.json.JSONObject;

import org.joda.time.DateTime;

/**
 * 日期工具类- 默认使用 "yyyy-MM-dd HH:mm:ss" 格式化日期
 * 
 * @author cren
 */
public class DateUtils
{
	public static String FORMAT_SHORT_NO_YEAR = "MM月dd日";

	/**
	 * 英文简写（默认）如：2010-12-01
	 */
	public static String FORMAT_SHORT = "yyyy-MM-dd";
	/** 时间格式 ‘年月日格式’. */
	public final static String DATE_YMD_FORMAT_SLANT = "yyyy/MM/dd";
	/**
	 * 英文全称 如：2010-12-01 23:15:06
	 */
	public static String FORMAT_LONG = "yyyy-MM-dd HH:mm:ss";

	public static String FORMAT_CONCAT = "yyMMddHHmmssSSS";

	public static String FORMAT_YYMMDDHHMMSS = "yyMMddHHmmss";
	public static String FORMAT_YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
	/**
	 * 精确到毫秒的完整时间 如：yyyy-MM-dd HH:mm:ss.S
	 */
	public static String FORMAT_FULL = "yyyy-MM-dd HH:mm:ss.S";
	/**
	 * 中文简写 如：2010年12月01日
	 */
	public static String FORMAT_SHORT_CN = "yyyy年MM月dd日";
	/**
	 * 中文全称 如：2010年12月01日 23时15分06秒
	 */
	public static String FORMAT_LONG_CN = "yyyy年MM月dd日  HH时mm分ss秒";
	/**
	 * 精确到毫秒的完整中文时间
	 */
	public static String FORMAT_FULL_CN = "yyyy年MM月dd日  HH时mm分ss秒SSS毫秒";
	public static String[] WEEKS = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };

	private static Map<String, Integer> WEEKS_OF_DAY_MAP = new HashMap<String, Integer>(12);

	/** 冒号集合.存放所有的冒号格式. */
	private static List<String> COLON_LIST = new ArrayList<String>(3);
	static
	{
		WEEKS_OF_DAY_MAP.put("星期一", 1);
		WEEKS_OF_DAY_MAP.put("星期二", 2);
		WEEKS_OF_DAY_MAP.put("星期三", 3);
		WEEKS_OF_DAY_MAP.put("星期四", 4);
		WEEKS_OF_DAY_MAP.put("星期五", 5);
		WEEKS_OF_DAY_MAP.put("星期六", 6);
		WEEKS_OF_DAY_MAP.put("星期日", 7);

		COLON_LIST.add(":");// 引文冒号.
		COLON_LIST.add("：");// 中文冒号.
	}

	/**
	 * 获得默认的 date pattern
	 */
	public static String getDatePattern()
	{
		return FORMAT_LONG;
	}

	/**
	 * 根据预设格式返回当前日期
	 * 
	 * @return
	 */
	public static String getNow()
	{
		return format(new Date());
	}

	/**
	 * 根据用户格式返回当前日期
	 * 
	 * @param format
	 * @return
	 */
	public static String getNow(String format)
	{
		return format(new Date(), format);
	}

	/**
	 * 使用预设格式格式化日期
	 * 
	 * @param date
	 * @return
	 */
	public static String format(Date date)
	{
		return format(date, getDatePattern());
	}

	/**
	 * 使用用户格式格式化日期
	 * 
	 * @param date
	 *            日期
	 * @param pattern
	 *            日期格式
	 * @return
	 */
	public static String format(Date date, String pattern)
	{
		String returnValue = "";
		if (date != null)
		{
			SimpleDateFormat df = new SimpleDateFormat(pattern);
			returnValue = df.format(date);
		}
		return (returnValue);
	}

	/**
	 * 使用预设格式提取字符串日期
	 * 
	 * @param strDate
	 *            日期字符串
	 * @return
	 */
	public static Date parse(String strDate)
	{
		return parse(strDate, getDatePattern());
	}

	/**
	 * 使用用户格式提取字符串日期
	 * 
	 * @param strDate
	 *            日期字符串
	 * @param pattern
	 *            日期格式
	 * @return
	 */
	public static Date parse(String strDate, String pattern)
	{
		SimpleDateFormat df = new SimpleDateFormat(pattern);
		try
		{
			return df.parse(strDate);
		}
		catch (ParseException e)
		{
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 在日期上增加数个整月
	 * 
	 * @param date
	 *            日期
	 * @param n
	 *            要增加的月数
	 * @return
	 */
	public static Date addMonth(Date date, int n)
	{
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.add(Calendar.MONTH, n);
		return cal.getTime();
	}

	public static Date addYear(Date date, int n)
	{
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.add(Calendar.YEAR, n);
		return cal.getTime();
	}

	/**
	 * 在日期上增加天数
	 * 
	 * @param date
	 *            日期
	 * @param n
	 *            要增加的天数
	 * @return
	 */
	public static Date addDay(Date date, int n)
	{
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.add(Calendar.DATE, n);
		return cal.getTime();
	}

	/**
	 * 在日期上增加天数.
	 * 
	 * @param basicDate
	 *            日期.
	 * @param day
	 *            天数.
	 * @return
	 */
	public static Date addDateByDay(Date basicDate, int day)
	{
		DateTime dt = new DateTime(basicDate);
		dt = dt.plusDays(day);
		return dt.toDate();
	}

	/**
	 * 获得指定日期的开始时间.<br />
	 * eg: 2015-04-22 18:21:59.999 转换后 2015-04-22 00:00:00.000
	 * 
	 * @param date
	 *            指定时间.
	 * @return
	 */
	public static Date getDateWithStart(Date date)
	{
		DateTime dt = new DateTime(date);
		DateTime newDate = new DateTime(dt.getYear(), dt.getMonthOfYear(), dt.getDayOfMonth(), 0, 0, 0, 0);
		return newDate.toDate();
	}

	/**
	 * 获得指定日期的结束时间.<br />
	 * eg: 2015-04-22 18:21:59.999 转换后 2015-04-22 23:59:59.999
	 * 
	 * @param date
	 *            指定时间.
	 * @return
	 */
	public static Date getDateWithEnd(Date date)
	{
		DateTime dt = new DateTime(date);
		DateTime newDate = new DateTime(dt.getYear(), dt.getMonthOfYear(), dt.getDayOfMonth(), 23, 59, 59, 999);
		return newDate.toDate();
	}

	/**
	 * 重新制定时间的小时和分钟.
	 * 
	 * @param date
	 * @param hourMinuteString
	 *            小时和分钟的字符串形式.eg 08:00
	 * @return
	 */
	public static Date buildDateWithHourMinute(Date date, String hourMinuteString)
	{
		String separator = ":";
		for (String string : COLON_LIST)
		{
			if (hourMinuteString.indexOf(string) != -1)
			{
				separator = string;
				break;
			}
		}

		String[] hourMinuteArray = hourMinuteString.split(separator);
		DateTime dt = new DateTime(getDateWithStart(date));
		dt = dt.plusHours(Integer.valueOf(hourMinuteArray[0].trim()));
		dt = dt.plusMinutes(Integer.valueOf(hourMinuteArray[1].trim()));
		return dt.toDate();
	}

	/**
	 * 根据传递的开始、结束时间，进行按时间升序排序.
	 * 
	 * @param begDate
	 *            开始时间
	 * @param endDate
	 *            结束时间
	 * @return 时间数组，[0] 开始时间， [1]结束时间.
	 */
	public static Date[] swapDateOrderAsc(Date begDate, Date endDate)
	{
		DateTime beg = new DateTime(begDate);
		DateTime end = new DateTime(endDate);
		if (beg.isBefore(end))
		{
			return new Date[] { begDate, endDate };
		}
		Date temp = null;
		temp = begDate;
		begDate = endDate;
		endDate = temp;
		return new Date[] { begDate, endDate };
	}

	/**
	 * 获取时间戳
	 */
	public static String getTimeString()
	{
		SimpleDateFormat df = new SimpleDateFormat(FORMAT_FULL);
		Calendar calendar = Calendar.getInstance();
		return df.format(calendar.getTime());
	}

	/**
	 * 获取日期年份
	 * 
	 * @param date
	 *            日期
	 * @return
	 */
	public static String getYear(Date date)
	{
		return format(date).substring(0, 4);
	}

	/**
	 * 按默认格式的字符串距离今天的天数
	 * 
	 * @param date
	 *            日期字符串
	 * @return
	 */
	public static int countDays(String date)
	{
		long t = Calendar.getInstance().getTime().getTime();
		Calendar c = Calendar.getInstance();
		c.setTime(parse(date));
		long t1 = c.getTime().getTime();
		return (int) (t / 1000 - t1 / 1000) / 3600 / 24;
	}

	/**
	 * 按用户格式字符串距离今天的天数
	 * 
	 * @param date
	 *            日期字符串
	 * @param format
	 *            日期格式
	 * @return
	 */
	public static int countDays(String date, String format)
	{
		long t = Calendar.getInstance().getTime().getTime();
		Calendar c = Calendar.getInstance();
		c.setTime(parse(date, format));
		long t1 = c.getTime().getTime();
		return (int) (t / 1000 - t1 / 1000) / 3600 / 24;
	}

	/**
	 * 计算两个日期之间相差的天数
	 * 
	 * @param smdate
	 *            较小的时间
	 * @param bdate
	 *            较大的时间
	 * @return 相差天数
	 * @throws ParseException
	 */
	public static int daysBetween(Date smdate, Date bdate) throws ParseException
	{
		SimpleDateFormat sdf = new SimpleDateFormat(getDatePattern());
		smdate = sdf.parse(sdf.format(smdate));
		bdate = sdf.parse(sdf.format(bdate));
		Calendar cal = Calendar.getInstance();
		cal.setTime(smdate);
		long time1 = cal.getTimeInMillis();
		cal.setTime(bdate);
		long time2 = cal.getTimeInMillis();
		long between_days = (time2 - time1) / (1000 * 3600 * 24);

		return Integer.parseInt(String.valueOf(between_days));
	}

	/**
	 * 获取日期对应的星期几 <br>
	 * 返回值 ： 星期日, 星期一, 星期二, 星期三, 星期四, 星期五, 星期六 <br>
	 * 
	 * @param date
	 * @return
	 */
	public static String getWeekOfCNDay(Date date)
	{
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		int week_index = cal.get(Calendar.DAY_OF_WEEK) - 1;
		if (week_index < 0)
		{
			week_index = 0;
		}
		return WEEKS[week_index];
	}

	/**
	 * 获取日期对应的星期数字 返回值：1,2,3,4,5,6,7 <br>
	 * 
	 * @param date
	 * @return
	 */
	public static int getWeekOfNumber(Date date)
	{
		String cnDays = getWeekOfCNDay(date);
		return WEEKS_OF_DAY_MAP.get(cnDays);
	}

	/**
	 * 获取类似 "04月15日 下午"格式.
	 * 
	 * @param d
	 *            Date.
	 * @return
	 */
	public static String formatMonthDayhour(Date d)
	{
		DateTime date = new DateTime(d);
		int hour = date.getHourOfDay();
		String hourString = "上午";
		if (hour > 18)
		{
			hourString = "晚上";
		}
		else if (hour < 12 && hour > 19)
		{
			hourString = "下午";
		}
		String str = date.toString(FORMAT_SHORT_NO_YEAR);

		StringBuilder sb = new StringBuilder(str.length() + 10);
		sb.append(str).append(" ").append(hourString);
		return sb.toString();
	}

	/**
	 * 判断是否超时指定时间.<br/>
	 * beginDate 是否 在 endDate 之后.
	 * 
	 * <pre>
	 * 例如：
	 * beginDate             : 2015-04-19T15:26:59.894+08:00 
	 * beginDate+second(12h) : 2015-04-20T03:26:59.894+08:00
	 * endDate               : 2015-04-20T00:00:00.000+08:00
	 * result                : true
	 * </pre>
	 * 
	 * @param beginDate
	 *            要比较的时间.
	 * @param endDate
	 *            基准时间.
	 * @param days
	 *            天.用于加在beginDate上.
	 * @param hours
	 *            小时.用于加在beginDate上.
	 * @param minutes
	 *            小时.用于加在beginDate上.
	 * @param second
	 *            秒.用于加在beginDate上.
	 * @return
	 */
	public static boolean verifyDateTimeout(Date beginDate, Date endDate, int days, int hours, int minutes, int second)
	{
		DateTime begin = new DateTime(beginDate); // 当前时间.
		DateTime end = new DateTime(endDate);// 截止时间.
		begin = begin.plusDays(days);
		begin = begin.plusHours(hours);
		begin = begin.plusMinutes(minutes);
		begin = begin.plusSeconds(second);
		return begin.isAfter(end);
	}

	/**
	 * 获取二个日期相差的月数.
	 * 
	 * @param start
	 * @param end
	 * @return
	 */
	public static int getMonthBetween(Date start, Date end)
	{
		if (start.after(end))
		{
			Date t = start;
			start = end;
			end = t;
		}
		Calendar startCalendar = Calendar.getInstance();
		startCalendar.setTime(start);
		Calendar endCalendar = Calendar.getInstance();
		endCalendar.setTime(end);
		Calendar temp = Calendar.getInstance();
		temp.setTime(end);
		temp.add(Calendar.DATE, 1);

		int year = endCalendar.get(Calendar.YEAR) - startCalendar.get(Calendar.YEAR);
		int month = endCalendar.get(Calendar.MONTH) - startCalendar.get(Calendar.MONTH);

		if ((startCalendar.get(Calendar.DATE) == 1) && (temp.get(Calendar.DATE) == 1))
		{
			return year * 12 + month + 1;
		}
		else if ((startCalendar.get(Calendar.DATE) != 1) && (temp.get(Calendar.DATE) == 1))
		{
			return year * 12 + month;
		}
		else if ((startCalendar.get(Calendar.DATE) == 1) && (temp.get(Calendar.DATE) != 1))
		{
			return year * 12 + month;
		}
		else
		{
			return (year * 12 + month - 1) < 0 ? 0 : (year * 12 + month);
		}
	}
	
	/**
	 * 获取两个时间相差的分钟数.
	 * 
	 * @param start
	 * @param end
	 * @return
	 */
	public static int getMinuteBetween(Date start, Date end)
	{
		if (start.after(end))
		{
			Date t = start;
			start = end;
			end = t;
		}
		long startMillisecond = start.getTime();
		long endMillisecond = end.getTime();
		return (int)(endMillisecond - startMillisecond)/60000;
	}
	
	public static Date[] getMonthOfDays(Date date)
	{
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		int maxDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);

		// calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) + 1);
		// 设置Calendar日期为下一个月一号
		calendar.set(Calendar.DATE, 1);
		// 设置Calendar日期减一,为本月末
		// calendar.add(Calendar.DATE, -1);

		Date[] days = new Date[maxDay];
		for (int i = 1; i <= maxDay; i++)
		{
			calendar.set(Calendar.DATE, i);
			days[i - 1] = calendar.getTime();
		}
		return days;
	}

	// 获得当前日期与本周一相差的天数
	private static int getMondayPlus(Date date)
	{
		Calendar cd = Calendar.getInstance();
		cd.setTime(date);
		// 获得今天是一周的第几天，星期日是第一天，星期二是第二天......
		int dayOfWeek = cd.get(Calendar.DAY_OF_WEEK);
		if (dayOfWeek == 1)
		{
			return -6;
		}
		else
		{
			return 2 - dayOfWeek;
		}
	}

	// 获得当前周- 周日 的日期
	public static String getPreviousSunday(Date date, String pattern)
	{
		int mondayPlus = getMondayPlus(date);
		GregorianCalendar currentDate = new GregorianCalendar();
		currentDate.setTime(date);
		currentDate.add(GregorianCalendar.DATE, mondayPlus + 6);
		Date monday = currentDate.getTime();
		// DateFormat df = DateFormat.getDateInstance();
		// String preMonday = df.format(monday);
		return format(monday, pattern);
	}

	// 获得当前周- 周一的日期
	public static String getCurrentMonday(Date date, String pattern)
	{
		int mondayPlus = getMondayPlus(date);
		GregorianCalendar currentDate = new GregorianCalendar();
		currentDate.add(GregorianCalendar.DATE, mondayPlus);
		Date monday = currentDate.getTime();
		SimpleDateFormat df = new SimpleDateFormat(pattern);
		String preMonday = df.format(monday);
		return preMonday;
	}

	/**
	 * 得到本月的第一天
	 * 
	 * @return
	 */
	public static String getMonthFirstDay(Date date, String pattern)
	{
		SimpleDateFormat sdf = new SimpleDateFormat(pattern);
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));

		return sdf.format(calendar.getTime());
	}
	
	public static Date getMonthFirstDayDate(Date date)
	{
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
        return getDateWithStart(calendar.getTime());
	}
	
	public static List<String> get11Monthly(Date date)
	{
		List<String> tmpSet = new ArrayList<String>(); 
		SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM");
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.MONTH, -12);
		for(int i =1;i<=11;i++){
			calendar.add(Calendar.MONTH, 1);
			String vString = sDateFormat.format(calendar.getTime());
			tmpSet.add(vString);
		}
        return tmpSet;
	}
	

	/**
	 * 得到本月的最后一天
	 * 
	 * @return
	 */
	public static String getMonthLastDay(Date date, String pattern)
	{
		SimpleDateFormat sdf = new SimpleDateFormat(pattern);
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
		return sdf.format(calendar.getTime());
	}

	/**
	 * 获取某年第一天日期
	 * 
	 * @param year
	 *            年份
	 * @return Date
	 */
	public static String getYearFirst(int year)
	{
		Calendar calendar = Calendar.getInstance();
		calendar.clear();
		calendar.set(Calendar.YEAR, year);
		Date currYearFirst = calendar.getTime();
		return format(currYearFirst, FORMAT_SHORT);
	}

	/**
	 * 获取某年最后一天日期
	 * 
	 * @param year
	 *            年份
	 * @return Date
	 */
	public static String getYearLast(int year)
	{
		Calendar calendar = Calendar.getInstance();
		calendar.clear();
		calendar.set(Calendar.YEAR, year);
		calendar.roll(Calendar.DAY_OF_YEAR, -1);
		Date currYearLast = calendar.getTime();
		return format(currYearLast, FORMAT_SHORT);
	}

	/**
	 * @Title: 比较两个时间差
	 * @Description: TODO
	 * @date 2016年3月16日
	 */
	public static JSONObject printDifference(Date startDate, Date endDate)
	{

		// milliseconds
		long different = endDate.getTime() - startDate.getTime();

		System.out.println("startDate : " + startDate);
		System.out.println("endDate : " + endDate);
		System.out.println("different : " + different);

		long secondsInMilli = 1000;
		long minutesInMilli = secondsInMilli * 60;
		long hoursInMilli = minutesInMilli * 60;
		long daysInMilli = hoursInMilli * 24;

		long elapsedDays = different / daysInMilli;
		different = different % daysInMilli;

		long elapsedHours = different / hoursInMilli;
		different = different % hoursInMilli;

		long elapsedMinutes = different / minutesInMilli;
		different = different % minutesInMilli;

		long elapsedSeconds = different / secondsInMilli;

		System.out.printf("%d 天, %d 小时, %d 分钟, %d 秒%n", elapsedDays, elapsedHours, elapsedMinutes, elapsedSeconds);
		JSONObject json = new JSONObject();
		json.put("days", elapsedDays);
		json.put("hours", elapsedHours);
		json.put("minutes", elapsedMinutes);
		json.put("seconds", elapsedSeconds);
		return json;
	}

}
